package com.bitoon.basketdudes.web.admin;

import com.bitoon.basketdudes.web.BaseAction;
import com.bitoon.basketdudes.web.datos.InfoCabeceraXHR;
import com.bitoon.basketdudes.web.jpa.AdmRol;
import com.bitoon.basketdudes.web.jpa.AdmUsuario;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.regex.*;

import java.util.*;
import javax.persistence.*;
import org.apache.log4j.Logger;

public class ListaUsuariosAdmin extends BaseAction {
    
    private List<AdmUsuario> datos;
    private InfoCabeceraXHR cabecera;
    private int pagina = 1;
    private int cuantos;

    // Parámetros de búsqueda de cadena
    private String cadena;
    //parametros para insertar/modificar un nuevo usuario
    private String idAdmin; //para recoger los ids de los usurios pasados
    private String nick;
    private String nickNuevo;
    private String email;
    private String password;
    private String fecha_alta;
    private String lenguaje;
    private int rol;
    private String accion;
    private String contrasenaSHA1;
    private AdmUsuario admin;

    private static String patternNick = "[0-9a-zA-Z._@#-]+";
    private static String patternEmail = "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}";

    private boolean insertar;
    private boolean error;
    private boolean modificar;

    private List<AdmRol> listaRoles;

    private Logger log = Logger.getLogger(ListaUsuariosAdmin.class);

    //acceso a la clase estatica BaseActionAdmin
    protected BaseActionAdmin bsaadmin = BaseActionAdmin.getInstance();

    @Override
    public String execute() {

        try {
            // El método sólo se ejecuta al principio, la paginación va por consultaXhr
            listaUsuarios(BaseActionAdmin.LISTADO_ADMINISTRADORES_ELEMENTOS_POR_PAGINA,BaseActionAdmin.LISTADO_ADMINISTRADORES_HUECOS_LADO_PAGINA);

        } catch (Exception e) {
            log.error("Error", e);
        }

        return SUCCESS;
    }

    public String elegirAccionUsuariosAdmin(){
        String retorno = "borrar";

        log.debug("Accion: " + getAccion() + " retorno: "+ retorno);

        if(getAccion().compareTo(retorno)!=0){

            retorno = "nueva";
        }

        return retorno;
    }

    public String consultaXhr() {

        listaUsuarios(cuantos, BaseActionAdmin.LISTADO_ADMINISTRADORES_HUECOS_LADO_PAGINA);

        return SUCCESS;
    }

    private void listaUsuarios(int elementos, int huecos) {
        List<AdmUsuario> retorno = null;
        EntityManager em = null;

        try {
            log.debug("Listando usuarios administradores");
            retorno = new ArrayList<AdmUsuario>();

            em = bsaadmin.getEmfAdmin().createEntityManager(); // checked
            
            Query q = em.createNamedQuery("AdmUsuario.findAllOrderByNick");
            
            int totalRegistros = q.getResultList().size();
            //log.debug("totalRegistros: " + totalRegistros);
            int totalPaginas = (totalRegistros-1)/elementos + 1;

            int offset = (pagina-1) * elementos;
            int first = (pagina-1)*elementos; //primer registro
            int max = elementos; //ultimo registro
            
            q = em.createNamedQuery("AdmUsuario.findAllOrderByNick");
            q.setFirstResult(first);
            q.setFirstResult(offset);
            q.setMaxResults(max);

            retorno = (List<AdmUsuario>)q.getResultList();

            log.debug("retorno: " + retorno.size());

            cabecera = new InfoCabeceraXHR();
            cabecera.setCorrecto(1);
            cabecera.setActual(pagina);
            cabecera.setTotal(totalPaginas);

            int p1=0, p2=0;

            if (pagina <= (huecos+1)) {
                p1 = 1;
                p2 = huecos*2 + 1;
            } else if (pagina >= (totalPaginas-huecos)) {
                p1 = totalPaginas - (huecos*2);
                p2 = totalPaginas;
            } else {
                p1 = pagina - huecos;
                p2 = pagina + huecos;
            }
            if (p1 < 1) {
                p1 = 1;
            }
            if (p2 > totalPaginas) {
                p2 = totalPaginas;
            }
            cabecera.setPrimeraPagina(p1);
            cabecera.setUltimaPagina(p2);

            setDatos(retorno);
            setCabecera(cabecera);

        } catch (Exception e) {
            log.error("[buscaUsuarios(String)]: Error: ", e);
        } finally {
            try { em.close(); } catch (Exception e) { }
        }
    }

    public String insertarUsuarioAdmin(){
        String retorno = SUCCESS;
        EntityManager em = null;

        log.debug("Inserto: " + isInsertar()+ "-" + nick + "-" + email + "-" + contrasenaSHA1 + "-" + fecha_alta + "-" + rol);

        try{
            //si hay que insertar un usuario administrador
            if(isInsertar()){
                if(datosValidos(nick,email)){
                    log.debug("Entro insertar");
                    em = bsaadmin.getEmfAdmin().createEntityManager(); // checked

                    em.getTransaction().begin();

                    AdmUsuario a = new AdmUsuario();

                    //hay que buscar al ultimo usuario insertado y asignarle el id+1 a este nuevo
                    Query q = em.createNamedQuery("AdmUsuario.findAllOrderById");

                    int ultimo_id = ((AdmUsuario)q.getResultList().get(0)).getId();

                    a.setId(++ultimo_id);
                    a.setEmail(email);
                    a.setLenguaje(lenguaje);
                    a.setNick(nick);
                    a.setPassword(contrasenaSHA1);

                    StringTokenizer st = new StringTokenizer(fecha_alta,"/");
                    String fechaDia = "";
                    String fechaMes = "";
                    String fechaAnio = "";
                    //si es española la noticia, el formato recibido es ddmmyyyy, sino es mmddyyyy
                    if(lenguaje.compareTo("es")==0){
                        fechaDia = st.nextToken().trim();
                        if(fechaDia.length()<2){
                            fechaDia = "0" + fechaDia;
                        }
                        fechaMes = st.nextToken().trim();
                        if(fechaMes.length()<2){
                            fechaMes = "0" + fechaMes;
                        }
                        fechaAnio = st.nextToken().trim();
                    }else{
                        fechaMes = st.nextToken();
                        if(fechaMes.length()<2){
                            fechaMes = "0" + fechaMes;
                        }
                        fechaDia = st.nextToken();
                        if(fechaDia.length()<2){
                            fechaDia = "0" + fechaDia;
                        }
                        fechaAnio = st.nextToken();
                    }

                    DateFormat df = new SimpleDateFormat("yyyyMMdd");
                    Date fcha = df.parse(fechaAnio+fechaMes+fechaDia);
                    a.setFAlta(fcha);
                    a.setFUltimo(fcha);
                    a.setRolId(new AdmRol(rol));

                    em.persist(a);

                    em.getTransaction().commit();
                }
                else{
                    //datos del nuevo usuario no válidos
                    setError(true);
                    retorno = ERROR;
                }//fin de comprobaciones de los datos
            }//fin si insertamos

             //cargo la lista de roles
            setListaRoles(cargarRoles());
                        
        } catch (Exception e) {
            log.error("[insertarUsuarioAdmin]: Error: ", e);
        } finally {
            try { em.close(); } catch (Exception e) { }
        }
        return retorno;
    }

    private boolean datosValidos(String nick,String email){
        boolean retorno = true; //por defecto es válido

        //que el nick tenga unos caracteres en croncreto
        if(nick.length()==0 || Pattern.matches(patternNick,nick)==false){
            log.debug("[Validacion] nick incorrecto");
            retorno = false;
        }

        //que sea un email y con los caracteres de un nick
        if(email.length()==0 || Pattern.matches(patternEmail,email)==false){
            log.debug("[Validacion] email incorrecto");
            retorno = false;
        }
        return retorno;
    }

    public String borrarUsuarioAdmin(){
        String retorno = SUCCESS;
        EntityManager em = null;

        //si se han seleccionado id's que borrar
        if(idAdmin!=null){
            try{
                em = bsaadmin.getEmfAdmin().createEntityManager(); // checked
                
                log.debug("[borrarUsuarioAdmin] id: " +idAdmin);
                StringTokenizer st = new StringTokenizer(idAdmin,",");
                String key ="";
                while(st.hasMoreTokens()) {
                    key = st.nextToken().trim();
                    //busco al usuario en la BD
                    Query q = em.createNamedQuery("AdmUsuario.findById");
                    log.debug("[borrarUsuarioAdmin] id: " +key);
                    q.setParameter("id", Integer.parseInt(key));
                   
                    AdmUsuario a = (AdmUsuario)q.getSingleResult();

                    //si hay usuario que borrar
                    if (a!=null){
                        em.getTransaction().begin();

                        em.remove(a);

                        em.getTransaction().commit();

                        log.debug("[borrarUsuarioAdmin] usuario con id: " + Integer.parseInt(key) +" borrado correctamente");
                    }
                }

            } catch (Exception e) {
                log.error("[borrarUsuarioAdmin]: Error: ", e);
            } finally {
                try { em.close(); } catch (Exception e) { }
            }
        }
        return retorno;
    }

    public String consultaUsuarioAdmin() {
        EntityManager em = null;
        String retorno = SUCCESS;

        if(isModificar()){
            //si hay que modificar la informacion
            retorno = modificarManager();
        }else{
            //si hay que consultar la información
            try {
                log.debug("Consulto: " + isModificar()+ "-" + nick);
                em = bsaadmin.getEmfAdmin().createEntityManager(); // checked

                Query q  = em.createNamedQuery("AdmUsuario.findByNick");
                q.setParameter("nick", nick);

                admin = (AdmUsuario)q.getSingleResult();

                if(admin==null){
                    //usuario encontrado
                    retorno = NOT_FOUND;
                }
            } catch (NoResultException e) {
                log.debug("[consultaUsuarioAdmin][usuario " + getNick() + " no encontrado]");
            } catch (Exception e) {
                log.error("[consultaUsuarioAdmin]: ", e);
            } finally {
                try { em.close(); } catch (Exception e) { }
            }
        }

        //cargo la lista de roles
        setListaRoles(cargarRoles());

        return retorno;
    }

    private List<AdmRol> cargarRoles(){

        List<AdmRol> lista = null;
        EntityManager em = null;

        try {
            log.debug("[cargarRoles]");
            em = bsaadmin.getEmfAdmin().createEntityManager(); // checked

            Query q  = em.createNamedQuery("AdmRol.findAll");

            lista = (ArrayList<AdmRol>)q.getResultList();

        } catch (NoResultException e) {
            log.debug("[cargarRoles] no hay roles]");
        } catch (Exception e) {
            log.error("[cargarRoles] error: ", e);
        } finally {
            try { em.close(); } catch (Exception e) { }
        }

        return lista;

    }

    private String modificarManager(){
        EntityManager em = null;
        String retorno = "mod_ok";

        log.debug("Modifico: " + isModificar()+ "-" + nick+ "-" + nickNuevo + "-" + email+ "-" + lenguaje+ "-" + rol);
        if(datosValidos(nickNuevo,email)){
            try {
                em = bsaadmin.getEmfAdmin().createEntityManager(); // checked

                Query q  = em.createNamedQuery("AdmUsuario.findByNick");
                q.setParameter("nick", nick);

                admin = (AdmUsuario)q.getSingleResult();

                if(admin!=null){
                    //usuario encontrado
                    em.getTransaction().begin();

                    //modifico
                    admin.setNick(nickNuevo);
                    admin.setEmail(email);
                    admin.setLenguaje(lenguaje);
                    admin.setRolId(new AdmRol(rol));

                    em.persist(admin);
                    em.getTransaction().commit();
                }

            } catch (NoResultException e) {
                log.debug("[modificarAdmin][usuario " + getNick() + " no encontrado]");
                retorno = NOT_FOUND;
                setError(true);
            } catch (Exception e) {
                log.error("[modificarAdmin]: ", e);
                setError(true);
            } finally {
                try { em.close(); } catch (Exception e) { }
            }
        }else{
            retorno ="mod_error";
            setError(true);
        }

        return retorno;
    }

    public List<AdmUsuario> getDatos() {
        return datos;
    }

    public void setDatos(List<AdmUsuario> resultado) {
        this.datos = resultado;
    }

    public int getPagina() {
        return pagina;
    }

    public void setPagina(int pagina) {
        this.pagina = pagina;
    }

    public int getCuantos() {
        return cuantos;
    }

    public void setCuantos(int cuantos) {
        this.cuantos = cuantos;
    }

    public InfoCabeceraXHR getCabecera() {
        return cabecera;
    }

    public void setCabecera(InfoCabeceraXHR cabecera) {
        this.cabecera = cabecera;
    }

    public String getCadena() {
        return cadena;
    }

    public void setCadena(String cadena) {
        this.cadena = cadena;
    }

    public boolean isInsertar() {
        return insertar;
    }

    public void setInsertar(boolean insertar) {
        this.insertar = insertar;
    }

    public String getNick() {
        return nick;
    }

    public void setNick(String nick) {
        this.nick = nick;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getFecha_alta() {
        return fecha_alta;
    }

    public void setFecha_alta(String fecha_alta) {
        this.fecha_alta = fecha_alta;
    }

    public String getLenguaje() {
        return lenguaje;
    }

    public void setLenguaje(String lenguaje) {
        this.lenguaje = lenguaje;
    }

    public int getRol() {
        return rol;
    }

    public void setRol(int rol) {
        this.rol = rol;
    }

    public boolean isError() {
        return error;
    }

    public void setError(boolean error) {
        this.error = error;
    }

    public String getAccion() {
        return accion;
    }

    public void setAccion(String accion) {
        this.accion = accion;
    }

    public String getContrasenaSHA1() {
        return contrasenaSHA1;
    }

    public void setContrasenaSHA1(String contrasenaSHA1) {
        this.contrasenaSHA1 = contrasenaSHA1;
    }

    public String getIdAdmin() {
        return idAdmin;
    }

    public void setIdAdmin(String idAdmin) {
        this.idAdmin = idAdmin;
    }

    public boolean isModificar() {
        return modificar;
    }

    public void setModificar(boolean modificar) {
        this.modificar = modificar;
    }

    public AdmUsuario getAdmin() {
        return admin;
    }

    public void setAdmin(AdmUsuario admin) {
        this.admin = admin;
    }

    public String getNickNuevo() {
        return nickNuevo;
    }

    public void setNickNuevo(String nicknuevo) {
        this.nickNuevo = nicknuevo;
    }

    public List<AdmRol> getListaRoles() {
        return listaRoles;
    }

    public void setListaRoles(List<AdmRol> listaRoles) {
        this.listaRoles = listaRoles;
    }

    public BaseActionAdmin getBsaadmin() {
        return bsaadmin;
    }

    public void setBsaadmin(BaseActionAdmin bsaadmin) {
        this.bsaadmin = bsaadmin;
    }

}